package com.my.netty.optimize.protocol;

import com.my.netty.optimize.config.Config;
import com.my.netty.optimize.message.Message;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToMessageCodec;
import lombok.extern.slf4j.Slf4j;

import java.util.List;

/**
 * 可以加@Sharable的自定义编解码器
 * 必须和LengthFieldBasedFrameDecoder一起使用，保证接收的ByteBuf是完整1条消息
 */
@Slf4j
@ChannelHandler.Sharable
public class MessageCodecSharable extends MessageToMessageCodec<ByteBuf, Message> {

    private byte[] MAGIC_NUM = new byte[]{1, 2, 3, 4};

    @Override
    protected void encode(ChannelHandlerContext ctx, Message msg, List<Object> list) throws Exception {
        //将msg序列化后写入out中
        ByteBuf out = ctx.alloc().buffer();
        //1. 4字节魔数
        out.writeBytes(MAGIC_NUM);
        //2. 1字节版本号
        out.writeByte(1);
        //3. 1字节序列化方式 jdk 0, json 1
        out.writeByte(Config.getSerializerAlgorithm().ordinal());
        //4. 1字节指令类型
        out.writeByte(msg.getMessageType());
        //5. 4字节消息序号
        out.writeInt(msg.getSequenceId());
        //1字节对齐，无业务含义
        out.writeByte(0xff);

        //6. 获取正文字节数组（目前只用JDK）
        /*
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(bos);
        oos.writeObject(msg);
        byte[] bytes = bos.toByteArray();
         */
        byte[] bytes = Config.getSerializerAlgorithm().serialize(msg);

        //写入正文长度
        out.writeInt(bytes.length);
        //7. 写入正文
        out.writeBytes(bytes);

        //需要将ByteBuf加入到list，才能给下一个Handler用
        list.add(out);
    }

    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> list) throws Exception {
        //读取魔数
        int magicNum = in.readInt();
        //读取版本
        byte version = in.readByte();
        //读取序列化方式
        byte serializerType = in.readByte();
        //读取指令类型
        byte msgType = in.readByte();
        //读取消息序号
        int sequenceId = in.readInt();
        //读取一字节填充值
        in.readByte();
        //读取正文长度
        int length = in.readInt();
        //读取正文字节
        byte[] bytes = new byte[length];
        in.readBytes(bytes, 0, length);
        //反序列化
        /*
        ObjectInputStream oin = new ObjectInputStream(new ByteArrayInputStream(bytes));
        Message message = (Message) oin.readObject();
         */
        //找到序列化算法
        Serializer.Algorithm serializer = Serializer.Algorithm.values()[serializerType];
        //JSON反序列化需要指定实际类型
        Message message = serializer.deserialize(Message.getMessageClass(msgType), bytes);

        log.debug("{}, {}, {}, {}, {}, {}", magicNum, version, serializerType, msgType, sequenceId, length);
//        log.debug("解码出Message {}", message);

        //解析出的对象需要加到list中，才能给下一个Handler用
        list.add(message);
    }
}
